﻿//
// Copyright (c) 2019-2022 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using AngouriMath;
using static AngouriMath.Entity.Number;
using Xunit;

namespace AngouriMath.Tests.Core
{
    public sealed class NumericDigits
    {
        void Test(Entity.Number n, string expected) => Assert.Equal(expected, n.Stringize());
        static readonly Complex i = Complex.ImaginaryOne;
        static readonly Complex pi = MathS.DecimalConst.pi;
        static readonly Complex e = MathS.DecimalConst.e;

        // Values are checked with Wolfram Alpha
        // Default precision is 100 digits
        [Fact] public void Pi() => Test(pi, "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068");
        [Fact] public void E() => Test(e, "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427");
        [Fact] public void Exp2() => Test(Exp(2), "7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121795");
        [Fact] public void ExpPiI() => Test(Exp(pi * i), "-1");
        [Fact] public void SqrtM3() => Test(Sqrt(-3), "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248576i");
        [Fact] public void SqrtI() => Test(Sqrt(i), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864 + 0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207862i");
        [Fact] public void Sqrt3P2I() => Test(Sqrt(3+2*i), "1.817354021023970620075194486035821926469403643127136112063307705827989943868365693678192017810062678 + 0.5502505227003375110556805653912514370755875596670069658341698224663216572058032360895012802789614795i");
        [Fact] public void Sqrt3M2I() => Test(Sqrt(3-2*i), "1.817354021023970620075194486035821926469403643127136112063307705827989943868365693678192017810062678 - 0.5502505227003375110556805653912514370755875596670069658341698224663216572058032360895012802789614795i");
        [Fact] public void Sin1() => Test(Sin(1), "0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526957");
        [Fact] public void SinI() => Test(Sin(i), "1.175201193643801456882381850595600815155717981334095870229565413013307567304323895607117452089623392i");
        [Fact] public void SinPi() => Test(Sin(i), "1.175201193643801456882381850595600815155717981334095870229565413013307567304323895607117452089623392i");
        [Fact] public void Sin3P2I() => Test(Sin(3+2*i), "0.5309210862485198052670400906606765596727734509514910300870685537180352875306706855293567300083225282 - 3.590564589985779952012565447794816793194913675729301509998621397417882680153461421522759381430149008i");
        [Fact] public void Sin3M2I() => Test(Sin(3-2*i), "0.5309210862485198052670400906606765596727734509514910300870685537180352875306706855293567300083225280 + 3.590564589985779952012565447794816793194913675729301509998621397417882680153461421522759381430149007i");
        [Fact] public void Cos1() => Test(Cos(1), "0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830896");
        [Fact] public void CosI() => Test(Cos(i), "1.543080634815243778477905620757061682601529112365863704737402214710769063049223698964264726435543036");
        [Fact] public void Cos3P2I() => Test(Cos(3+2*i), "-3.724545504915322565473970703255972528674965773215330726785894568664950105906529288911014829414174408 - 0.5118225699873846088344638498018756342455566094907438674553837912358533904574111940998404122618726230i");
        [Fact] public void Cos3M2I() => Test(Cos(3-2*i), "-3.724545504915322565473970703255972528674965773215330726785894568664950105906529288911014829414174407 + 0.5118225699873846088344638498018756342455566094907438674553837912358533904574111940998404122618726228i");
        [Fact] public void Tan1() => Test(Tan(1), "1.557407724654902230506974807458360173087250772381520038383946605698861397151727289555099965202242983");
        [Fact] public void TanI() => Test(Tan(i), "0.7615941559557648881194582826047935904127685972579365515968105001219532445766384834589475216736767144i");
        [Fact] public void Tan3P2I() => Test(Tan(3+2*i), "-0.009884375038322493720314034303501210979618133534670390318610106061155603556792543443355828521930418933 + 0.9653858790221331242784802693945606858797296500057577736369082400666397728539675500957543613480053582i");
        [Fact] public void Tan3M2I() => Test(Tan(3-2*i), "-0.009884375038322493720314034303501210979618133534670390318610106061155603556792543443355828521930418933 - 0.9653858790221331242784802693945606858797296500057577736369082400666397728539675500957543613480053582i");
        [Fact] public void Cotan1() => Test(Cotan(1), "0.6420926159343307030064199865942656202302781139181713791011622804262768568391646721984829197601968050");
        [Fact] public void CotanPi() => Test(Cotan(pi), "NaN");
        [Fact] public void CotanHalfPi() => Test(Cotan(0.5m * pi), "0");
        [Fact] public void CotanI() => Test(Cotan(i), "-1.313035285499331303636161246930847832912013941240452655543152967567084270461874382674679241480856303i");
        [Fact] public void Cotan3P2I() => Test(Cotan(3+2*i), "-0.0106047834703371017503168962077792923972675909391407246475487930531248300454417108979266267185038252 - 1.035746637764995396112758656897908320248306959923214042664373819742665974520371256149665849444234282i");
        [Fact] public void ArcsinM2() => Test(Arcsin(-2), "-1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534 - 1.316957896924816708625046347307968444026981971467516479768472256920460185416443976074219013450101788i");
        [Fact] public void Arcsin1() => Test(Arcsin(1), "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534");
        [Fact] public void Arcsin3() => Test(Arcsin(3), "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534 - 1.762747174039086050465218649959584618056320656523270821506591217306754368444052175667413783820512091i");
        [Fact] public void Arcsin4() => Test(Arcsin(4), "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534 - 2.063437068895560546727281172620131871456591449883392499836032692765902842847409911780353006403580318i");
        [Fact] public void Arcsin3M2I() => Test(Arcsin(3-2*i), "0.9646585044076027920454110594995323555197773725073316527132580297155508786089335572049608301897631770 - 1.968637925793096291788665095245498189520731012682010573842811017352748255492485345887875752070076217i");
        [Fact] public void Arcsin3P2I() => Test(Arcsin(3+2*i), "0.9646585044076027920454110594995323555197773725073316527132580297155508786089335572049608301897631770 + 1.968637925793096291788665095245498189520731012682010573842811017352748255492485345887875752070076217i");
        [Fact] public void ArcsinI() => Test(Arcsin(i), "0.8813735870195430252326093249797923090281603282616354107532956086533771842220260878337068919102560457i");
        [Fact] public void ArccosM2() => Test(Arccos(-2), "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 + 1.316957896924816708625046347307968444026981971467516479768472256920460185416443976074219013450101788i");
        [Fact] public void Arccos1() => Test(Arccos(1), "0");
        [Fact] public void Arccos3() => Test(Arccos(3), "1.762747174039086050465218649959584618056320656523270821506591217306754368444052175667413783820512091i");
        [Fact] public void Arccos4() => Test(Arccos(4), "2.063437068895560546727281172620131871456591449883392499836032692765902842847409911780353006403580318i");
        [Fact] public void ArccosI() => Test(Arccos(i), "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534 - 0.8813735870195430252326093249797923090281603282616354107532956086533771842220260878337068919102560457i");
        [Fact] public void Arccos3P2I() => Test(Arccos(3+2*i), "0.6061378223872938271859106321402190865788073271802212577742142664383573245341709421090565824812953570 - 1.968637925793096291788665095245498189520731012682010573842811017352748255492485345887875752070076217i");
        [Fact] public void Arctan1() => Test(Arctan(1), "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670");
        [Fact] public void ArctanI() => Test(Arctan(i), "+ooi");
        [Fact] public void Arctan3P2I() => Test(Arctan(3+2*i), "1.338972522294493561124193575909144241084316172544492778582005751793809271060233646663717270678614588 + 0.1469466662255297520474327851547159424423449403442452953891851939502023996823900422792744078835711450i");
        [Fact] public void Arccotan1() => Test(Arccotan(1), "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670");
        [Fact] public void ArccotanI() => Test(Arccotan(i), "-ooi");
        [Fact] public void Arccotan3P2I() => Test(Arccotan(3+2*i), "0.2318238045004030581071281157306072010142685271430601319054665443600989320828708526503001419924439467 - 0.1469466662255297520474327851547159424423449403442452953891851939502023996823900422792744078835711419i");
        [Fact] public void Log10_1() => Test(Log(10, 1), "0");
        [Fact] public void Log10_0() => Test(Log(10, 0), "-oo");
        [Fact] public void LogI_I() => Test(Log(i, i), "1");
        [Fact] public void LogI_1() => Test(Log(i, 1), "0");
        [Fact] public void LogI_M1() => Test(Log(i, -1), "2");
        [Fact] public void LogI_2() => Test(Log(i, 2), "-0.4412712003053031867929128642359953819653794974593109409785264674142435340933733649959862237079351117i");
        [Fact] public void LogM2_M2() => Test(Log(-2, -2), "1");
        [Fact] public void LogM2_0D5() => Test(Log(-2, 0.5m), "-0.04642032354540812805739794967614531473517486433229878976878405934128995144281958985056393738882100657 + 0.2103936242079302074624500066187461838994455574074656160548588507113367960711277189504016452320136900i");
        [Fact] public void LogM2_0D4() => Test(Log(-2, 0.4m), "-0.06136432986843633646517722130553639639897513966073574085079108126276417408725123183789917075670358045 + 0.2781252428256368191899557377147340479778729417292667461789200592366343982454240662260594052903331773i");
        [Fact] public void LogM2_3P2I() => Test(Log(-2, 3+2*i), "0.2643664916612894989375747779599512529839212984780690192522150852389360266747092012500969179019942127 - 0.3498957094724448147885913933302844456684320929581102596014846703961864239635800903604529923905776475i");
        [Fact] public void LnE() => Test(Ln(e), "1");
        [Fact] public void LnPi() => Test(Ln(pi), "1.144729885849400174143427351353058711647294812915311571513623071472137769884826079783623270275489713");
        [Fact] public void Pow2_3() => Test(Pow(2, 3), "8");
        [Fact] public void Pow2_I() => Test(Pow(2, i), "0.7692389013639721265783299936612707014408959949119638531698715074290813468073407890597897424260168072 + 0.6389612763136348011500329114647017842572305378305797294955869566463245224485447499034456609322567386i");
        [Fact] public void PowI_2() => Test(Pow(i, 2), "-1");
        [Fact] public void PowI_I() => Test(Pow(i, i), "0.2078795763507619085469556198349787700338778416317696080751358830554198772854821397886002778654260353");
        [Fact] public void Pow0D5M0D8I_0D5() => Test(Pow(0.5m-0.8m*i, 0.5m), "0.8495287261787150364907695626370349126367049237188233590072351305588742785045041120988684216395800850 - 0.4708492928770629369416080841473292873459093837847060526082076263776372676635818831502937646218684434i");
        [Fact] public void Sqrt0D5M0D8I() => Test(Sqrt(0.5m-0.8m*i), "0.8495287261787150364907695626370349126367049237188233590072351305588742785045041120988684216395800853 - 0.4708492928770629369416080841473292873459093837847060526082076263776372676635818831502937646218684426i");
        [Fact] public void Pow3P2I_3M2I() => Test(Pow(3+2*i,3-2*i), "105.7489754858859776057429151808913270583911891854438642007164406579203854865458413612560669739008029 - 109.0885464095191985068230453514141449073149001480712525014939233398460315014292268679635166428957493i");
        [Fact] public void Pow3P2I_3P2I() => Test(Pow(3+2*i,3+2*i), "-5.409738793917671859317094187110414923431153201422932321801121451217085143160320149482544245235856011 - 13.41044237041274830872806422189982707487514435448700312177401211574208044465073698802176970443887716i");
        [Fact] public void Pow3M2I_3M2I() => Test(Pow(3-2*i,3-2*i), "-5.409738793917671859317094187110414923431153201422932321801121451217085143160320149482544245235856011 + 13.41044237041274830872806422189982707487514435448700312177401211574208044465073698802176970443887716i");
        [Fact] public void Pow3M2I_3P2I() => Test(Pow(3-2*i,3+2*i), "105.7489754858859776057429151808913270583911891854438642007164406579203854865458413612560669739008029 + 109.0885464095191985068230453514141449073149001480712525014939233398460315014292268679635166428957493i");
        [Fact] public void FactorialM1() => Test(Factorial(-1), "NaN");
        [Fact] public void Factorial1() => Test(Factorial(1), "1");
        [Fact] public void FactorialI() => Test(Factorial(i), "0.4980156681183560427136911174621980919529629675876500928926429549984583004359819345078945042826705814 - 0.1549498283018106851249551304838866051958796520793249302658802767988608014911385390129513664794630707i");
        [Fact] public void Factorial3P2I() => Test(Factorial(3+2*i), "-3.011540370326620221673638953203521589699578522491818592806991348873731233891102261040571052079905478 + 1.770168194467116248779870937552670949490317426560124022588414061948659734862964828539391156632034635i");
        [Fact] public void Factorial3M2I() => Test(Factorial(3-2*i), "-3.011540370326620221673638953203521589699578522491818592806991348873731233891102261040571052079905478 - 1.770168194467116248779870937552670949490317426560124022588414061948659734862964828539391156632034635i");
        [Fact] public void GammaM1() => Test(Gamma(-1), "NaN");
        [Fact] public void Gamma1() => Test(Gamma(1), "1");
        [Fact] public void GammaI() => Test(Gamma(i), "-0.1549498283018106851249551304838866051958796520793249302658802767988608014911385390129513664794630707 - 0.4980156681183560427136911174621980919529629675876500928926429549984583004359819345078945042826705814i");
        [Fact] public void Gamma3P2I() => Test(Gamma(3+2*i), "-0.4226372863112021667277826911157863746244692857196313640957035325172210947651828558494562186904343972 + 0.8718142556965068607451454399280812329130853326664622502599403756610339747977768467461011980043011430i");
        [Fact] public void Gamma3M2I() => Test(Gamma(3-2*i), "-0.4226372863112021667277826911157863746244692857196313640957035325172210947651828558494562186904343972 - 0.8718142556965068607451454399280812329130853326664622502599403756610339747977768467461011980043011430i");
    }
}
